package com.ht.modules.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ht.constant.CommonConstant;
import com.ht.entity.SysPermissionDataRule;
import com.ht.modules.system.entity.SysPermission;
import com.ht.exception.JeecgBootException;
import com.ht.modules.system.mapper.SysPermissionMapper;
import com.ht.modules.system.model.TreeModel;
import com.ht.modules.system.service.ISysPermissionDataRuleService;
import com.ht.modules.system.service.ISysPermissionService;
import com.ht.utils.oConvertUtils;
import jakarta.annotation.Resource;
import org.apache.logging.log4j.util.Strings;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 菜单权限表 服务实现类
 */
@Service
public class SysPermissionServiceImpl extends ServiceImpl<SysPermissionMapper, SysPermission> implements ISysPermissionService {

    @Resource
    private SysPermissionMapper sysPermissionMapper;

    @Resource
    private ISysPermissionDataRuleService permissionDataRuleService;

    @Override
    public List<TreeModel> queryListByParentId(String parentId) {
        return sysPermissionMapper.queryListByParentId(parentId);
    }

    /**
     * 真实删除
     */
    @Override
    @Transactional
    @CacheEvict(value = "permission", allEntries = true)
    public void deletePermission(String id) throws JeecgBootException {
        SysPermission sysPermission = this.getById(id);
        if (sysPermission == null) {
            throw new JeecgBootException("未找到菜单信息");
        }
        String pid = sysPermission.getParentId();
        long count = this.count(new QueryWrapper<SysPermission>().lambda().eq(SysPermission::getParentId, pid));
        if (count == 1) {
            //若父节点无其他子节点，则该父节点是叶子节点
            this.sysPermissionMapper.setMenuLeaf(pid, 1);
        }
        sysPermissionMapper.deleteById(id);
        // 该节点可能是子节点但也可能是其它节点的父节点,所以需要级联删除
        this.removeChildrenBy(sysPermission.getId());
    }

    /**
     * 根据父id删除其关联的子节点数据
     */
    public void removeChildrenBy(String parentId) {
        LambdaQueryWrapper<SysPermission> query = new LambdaQueryWrapper<>();
        // 封装查询条件parentId为主键,
        query.eq(SysPermission::getParentId, parentId);
        // 查出该主键下的所有子级
        List<SysPermission> permissionList = this.list(query);
        if (permissionList != null && !permissionList.isEmpty()) {
            String id; // id
            long num; // 查出的子级数量
            // 如果查出的集合不为空, 则先删除所有
            this.remove(query);
            // 再遍历刚才查出的集合, 根据每个对象,查找其是否仍有子级
            for (SysPermission sysPermission : permissionList) {
                id = sysPermission.getId();
                num = this.count(new LambdaQueryWrapper<SysPermission>().eq(SysPermission::getParentId, id));
                // 如果有, 则递归
                if (num > 0) {
                    this.removeChildrenBy(id);
                }
            }
        }
    }

    /**
     * 逻辑删除
     */
    @Override
    @CacheEvict(value = "permission", allEntries = true)
    //@CacheEvict(value = "permission",allEntries=true,condition="#sysPermission.menuType==2")
    public void deletePermissionLogical(String id) throws JeecgBootException {
        SysPermission sysPermission = this.getById(id);
        if (sysPermission == null) {
            throw new JeecgBootException("未找到菜单信息");
        }
        String pid = sysPermission.getParentId();
        long count = this.count(new QueryWrapper<SysPermission>().lambda().eq(SysPermission::getParentId, pid));
        if (count == 1) {
            //若父节点无其他子节点，则该父节点是叶子节点
            this.sysPermissionMapper.setMenuLeaf(pid, 1);
        }
        sysPermission.setDelFlag(1);
        this.updateById(sysPermission);
    }

    @Override
    @CacheEvict(value = "permission", allEntries = true)
    public void addPermission(SysPermission sysPermission) throws JeecgBootException {
        //----------------------------------------------------------------------
        //判断是否是一级菜单，是的话清空父菜单
        if (CommonConstant.MENU_TYPE_0.equals(sysPermission.getMenuType())) {
            sysPermission.setParentId(null);
        }
        //----------------------------------------------------------------------
        String pid = sysPermission.getParentId();
        if (oConvertUtils.isNotEmpty(pid)) {
            //设置父节点不为叶子节点
            this.sysPermissionMapper.setMenuLeaf(pid, 0);
        }
        sysPermission.setCreateTime(new Date());
        sysPermission.setDelFlag(0);
        sysPermission.setLeaf(true);
        this.save(sysPermission);
    }

    @Override
    @CacheEvict(value = "permission", allEntries = true)
    public void editPermission(SysPermission sysPermission) throws JeecgBootException {
        SysPermission p = this.getById(sysPermission.getId());
        //TODO 该节点判断是否还有子节点
        if (p == null) {
            throw new JeecgBootException("未找到菜单信息");
        } else {
            sysPermission.setUpdateTime(new Date());
            //----------------------------------------------------------------------
            //Step1.判断是否是一级菜单，是的话清空父菜单ID
            if (CommonConstant.MENU_TYPE_0.equals(sysPermission.getMenuType())) {
                sysPermission.setParentId("");
            }
            //Step2.判断菜单下级是否有菜单，无则设置为叶子节点
            long count = this.count(new QueryWrapper<SysPermission>().lambda().eq(SysPermission::getParentId, sysPermission.getId()));
            if (count == 0) {
                sysPermission.setLeaf(true);
            }
            //----------------------------------------------------------------------
            this.updateById(sysPermission);

            //如果当前菜单的父菜单变了，则需要修改新父菜单和老父菜单的，叶子节点状态
            String pid = sysPermission.getParentId();
            if ((oConvertUtils.isNotEmpty(pid) && !pid.equals(p.getParentId())) || oConvertUtils.isEmpty(pid) && oConvertUtils.isNotEmpty(p.getParentId())) {
                //configVo.设置新的父菜单不为叶子节点
                this.sysPermissionMapper.setMenuLeaf(pid, 0);
                //b.判断老的菜单下是否还有其他子菜单，没有的话则设置为叶子节点
                long cc = this.count(new QueryWrapper<SysPermission>().lambda().eq(SysPermission::getParentId, p.getParentId()));
                if (cc == 0) {
                    this.sysPermissionMapper.setMenuLeaf(p.getParentId(), 1);
                }

            }
        }

    }

    @Override
    public List<SysPermission> queryByUser(String username) {
        return this.sysPermissionMapper.queryByUser(username);
    }

    /**
     * 根据permissionId删除其关联的SysPermissionDataRule表中的数据
     */
    @Override
    public void deletePermRuleByPermId(String id) {
        LambdaQueryWrapper<SysPermissionDataRule> query = new LambdaQueryWrapper<>();
        query.eq(SysPermissionDataRule::getPermissionId, id);
        long countValue = this.permissionDataRuleService.count(query);
        if (countValue > 0) {
            this.permissionDataRuleService.remove(query);
        }
    }

    /**
     * 获取模糊匹配规则的数据权限URL
     */
    @Override
    @Cacheable(value = "permission")
    public List<String> queryPermissionUrlWithStar() {
        return this.baseMapper.queryPermissionUrlWithStar();
    }

    @Override
    public List<String> getAllRoleByUrl(String url) {
        return sysPermissionMapper.getAllRoleByUrl(url);
    }

    @Override
    public List<Map<String, String>> getAndroidPermissionByToken(String username, String path) {
        return sysPermissionMapper.getAndroidPermissionByToken(username, path);
    }

    @Override
    public List<String> generateSql(String ids) {
        List<String> result = new ArrayList<>();
        List<String> permissionIdList = Arrays.asList(ids.split(","));
        List<SysPermission> allPermissionList = this.list(new LambdaQueryWrapper<SysPermission>()
                .isNotNull(SysPermission::getParentId)
                .orderByAsc(SysPermission::getSortNo));
        Map<String, List<SysPermission>> allPermissionMap = allPermissionList.stream().collect(Collectors.groupingBy(SysPermission::getParentId));

        List<SysPermission> needGenerateDataList = new ArrayList<>();
        for (SysPermission permission : allPermissionList) {
            if (permissionIdList.contains(permission.getId())) {
                needGenerateDataList.add(permission);
                this.findChildrenPermissionList(allPermissionMap, permission.getId(), needGenerateDataList);
            }
        }

        String permissionSqlPrefix = "INSERT INTO sys_permission " +
                "(id, parent_id, name, url, component, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, " +
                "is_route, is_leaf, hidden, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status) VALUES";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (SysPermission permission : needGenerateDataList) {
            String annotation = "-- 菜单名称：" + permission.getName();
            result.add(annotation);
            String permissionSql = "('"
                    + permission.getId() + "',"
                    + (Strings.isBlank(permission.getParentId()) ? "NULL" : "'" + permission.getParentId() + "'") + ","
                    + (Strings.isBlank(permission.getName()) ? "NULL" : "'" + permission.getName() + "'") + ","
                    + (Strings.isBlank(permission.getUrl()) ? "NULL" : "'" + permission.getUrl().replaceAll("'", "\\\\'") + "'") + ","
                    + (Strings.isBlank(permission.getComponent()) ? "NULL" : "'" + permission.getComponent() + "'") + ","
                    + (Strings.isBlank(permission.getComponentName()) ? "NULL" : "'" + permission.getComponentName() + "'") + ","
                    + (Strings.isBlank(permission.getRedirect()) ? "NULL" : "'" + permission.getRedirect() + "'") + ","
                    + (null == permission.getMenuType() ? "NULL" : permission.getMenuType()) + ","
                    + (Strings.isBlank(permission.getPerms()) ? "NULL" : "'" + permission.getPerms() + "'") + ","
                    + (Strings.isBlank(permission.getPermsType()) ? "NULL" : "'" + permission.getPermsType() + "'") + ","
                    + (null == permission.getSortNo() ? "NULL" : permission.getSortNo()) + ","
                    + (permission.isAlwaysShow() ? 1 : 0) + ","
                    + (Strings.isBlank(permission.getIcon()) ? "NULL" : "'" + permission.getIcon() + "'") + ","
                    + (permission.isRoute() ? 1 : 0) + ","
                    + (permission.isLeaf() ? 1 : 0) + ","
                    + (permission.isHidden() ? 1 : 0) + ","
                    + (Strings.isBlank(permission.getDescription()) ? "NULL" : "'" + permission.getDescription() + "'") + ","
                    + (Strings.isBlank(permission.getCreateBy()) ? "NULL" : "'" + permission.getCreateBy() + "'") + ","
                    + (null == permission.getCreateTime() ? "NULL" : "'" + sdf.format(permission.getCreateTime()) + "'") + ","
                    + (Strings.isBlank(permission.getUpdateBy()) ? "NULL" : "'" + permission.getUpdateBy() + "'") + ","
                    + (null == permission.getUpdateTime() ? "NULL" : "'" + sdf.format(permission.getUpdateTime()) + "'") + ","
                    + (null == permission.getDelFlag() ? "NULL" : permission.getDelFlag()) + ","
                    + (null == permission.getRuleFlag() ? "NULL" : permission.getRuleFlag()) + ","
                    + (Strings.isBlank(permission.getStatus()) ? "NULL" : "'" + permission.getStatus() + "'")
                    + ");";
            result.add(permissionSqlPrefix + permissionSql);
        }
        return result;
    }

    private void findChildrenPermissionList(Map<String, List<SysPermission>> allPermissionMap, String parentId, List<SysPermission> needGenerateDataList) {
        if (allPermissionMap.containsKey(parentId)) {
            List<SysPermission> permissionList = allPermissionMap.get(parentId);
            for (SysPermission permission : permissionList) {
                needGenerateDataList.add(permission);
                this.findChildrenPermissionList(allPermissionMap, permission.getId(), needGenerateDataList);
            }
        }
    }

}
